import * as puppeteer from 'puppeteer';
import Puppeteer, { Opt } from '../api/Puppeteer';
import * as moment from 'moment';
import {clone} from 'lodash';
import {mkdir,access}from 'fs'
import { resolve } from 'url';
import { project_config } from '../api/Config';


export default class PuppeteerImp implements Puppeteer {
    browser:puppeteer.Browser;
    page:puppeteer.Page;

    export:any = {
        测试项目名称:'',
        测试人:'',
        日期:'',
        功能:[]
    };

    emptyFunctionInfo = {
        功能:{
            功能名称:'',
            开始时间:'',
            结束时间:'',
            状态:'',
            步骤:[]
        }
    };

    emptyStepInfo = {
        名称:'',
        URL:'',
        状态:''
    }

    constructor(projectName:string,tester:string){

        //初始化项目基本信息
        this.export.测试项目名称 = projectName;
        this.export.测试人 = tester;
        this.export.日期 = this.getCurrentDate();
    }

    /**
     * 浏览器初始化
     * @param LaunchOpt 加载选项
     * @param Goto 跳转url
     * @param Size 浏览器size
     */
    async init(Size={width:980,height:1440}):Promise<void>{

        //克隆要添加的参数信息
        let functionResult = clone(this.emptyFunctionInfo);
        let stepResult = clone(this.emptyStepInfo);

        try {
            //初始化puppeteer browser和page
            this.browser = await puppeteer.launch(project_config.launchOpt);
            this.page = await this.browser.newPage();
            await this.page.setViewport(Size);
        } catch (error) {
            console.log(`测试数据初始化失败：${error}`)
        }

        //添加功能信息
        functionResult.功能.功能名称 = '首页';
        functionResult.功能.开始时间 = this.getCurrentDate();

        try {
            //添加步骤信息
            await this.page.goto(project_config.Goto);
            
            stepResult.名称 = 'goto 首页';
            functionResult.功能.状态 = '成功';
            stepResult.状态 = '成功';
        } catch (error) {

            functionResult.功能.状态 = '失败';
            stepResult.状态 = '失败';
            
        }finally{
            try {
                await this.shot('goto页面');
                stepResult.URL = await this.getShotUrl('初始化首页');
            } catch (error) {
                console.log (error)
            }
            
            functionResult.功能.结束时间 = this.getCurrentDate();
            functionResult.功能.步骤.push(stepResult);
            this.export.功能.push(functionResult.功能);
            console.log(JSON.stringify( this.export))
        }
    }

    /**
     * 获取时间
     */
    getCurrentDate(format:string='YYYY-MM-DD HH:mm:ss'):string{
        return moment(Date.now()).format(format);
    }

    /**
     * 处理路由
     * @param url 路由
     */
    getShotUrl(shotName:string):Promise<string>{

        //截图目录存放路径正则
        let reg = /^\w+\/\w+\/$/g
        let resultList = reg.exec(project_config.shotDir);
        if(!resultList){
            throw '截图目录格式不正确'
        }
        //生成目录,resolve path
        return new Promise((resolve,reject)=>{
            access(project_config.shotDir,e=>{
                if(e){
                    mkdir(project_config.shotDir,e=>{
                        if(e){
                            reject(e);
                        }else{
                            resolve(`${project_config.shotDir}${shotName}.png`)
                        }
                    })
                }else{
                    resolve(`${project_config.shotDir}${shotName}.png`)
                }
            })

        })
    }

    /**
     * 单个选择
     * @param selector 
     */
    async selectDom(selector:string):Promise<puppeteer.ElementHandle<Element>>{
        try {
            return await this.page.$(`${selector}`);
        } catch (error) {
            throw '没有找到dom'
        }
    };

    /**
     * 多个选择
     * @param selector 
     */
    async selectDoms(selector:string):Promise<puppeteer.ElementHandle<Element>[]>{
        try {
            return await this.page.$$(`${selector}`);
        } catch (error) {
            throw '没有找到dom'
        }
    }

    /**
     * 点击之后截图
     * @param selector 选择器
     * @param shotName 截图名字
     */
    async clickThenShot(selector:string, shotName?:string ):Promise<Step>{

        //克隆步骤对象
        let stepResult = clone(this.emptyStepInfo);
        try {
            let selectResult =  await this.selectDom(selector);//获取选择内容
            await selectResult.click();

            stepResult.状态 = '成功';
        } catch (error) {
            stepResult.状态 = '失败';
        }finally{
            if(shotName){
                try {
                    await this.shot(shotName).then(async()=>{
                        stepResult.URL = await this.getShotUrl(shotName);
                        stepResult.名称 = shotName;
                    })
                    return stepResult;
                } catch (error) {
                    console.log(error)
                }
            }
        }
        
    };

    /**
     * 触摸之后截图
     * @param selector 选择器
     * @param shotName 截图名字
     */
    async tapThenShot(selector:string, shotName?:string):Promise<Step>{

        //克隆步骤对象
        let stepResult = clone(this.emptyStepInfo);

        try {
            let selectResult =  await this.selectDom(selector);
            await selectResult.tap();
            stepResult.状态 = '成功';

        } catch (error) {
            stepResult.状态 = '失败'
        }finally{
            try {
                if(shotName){
                    await this.shot(shotName).then(async()=>{
                        stepResult.URL = await this.getShotUrl(shotName);
                        stepResult.名称 = shotName;
                    })
                    return stepResult;
                }
            } catch (error) {
                console.log(error);
            }
        }
    };

    /**
     * 截图
     * @param shotName 截图名字
     */
    async shot(shotName:any,shotOpt:puppeteer.ScreenshotOptions={}):Promise<void>{

        try {
            let shotUrl = await this.getShotUrl(shotName);
            shotOpt.path = shotUrl;
            await this.page.screenshot(shotOpt);
        } catch (error) {
            throw '截图失败'
        }
    };

    /**
     * 输入值
     * @param selector 选择器
     * @param value 值string
     * @param shotName 截图名字
     */
    async inputValue(selector:string, value:string, shotName?:string):Promise<Step>{
        //克隆步骤
        let stepResult = clone(this.emptyStepInfo);
        try {
            //输入
            let input =  await this.selectDom(selector);
            await input.type(value);
            stepResult.状态 = '成功'
        } catch (error) {
            stepResult.状态 = '失败';
        }finally{
            try {
                if(shotName){
                    //截图
                    await this.shot(shotName).then(async()=>{
                        stepResult.URL = await this.getShotUrl(shotName);
                        stepResult.名称 = shotName;
                    })
                    return stepResult;
                }
            } catch (error) {
                console.log(error)
            }
        }
    };

    /**
     * 关闭浏览器
     */
    async closeBrowser(){
       await this.browser.close();
    }
}
/**
 * 报告数据格式
 */
export interface ReportFormat{
    测试项目名称:string,
    测试人:string,
    日期:string,
    功能:Array<Func>
}

/**
 * 功能数据格式
 */
export interface Func{
    功能名称:string,
    开始时间:string,
    结束时间:string,
    状态:string,
    步骤:Array<Step>
}

/**
 * 步骤数据格式
 */
export interface Step{
    名称:string,
    URL:string,
    状态:string
}

export const EmptyReportFormat = {
    测试项目名称:'',
    测试人:'',
    日期:'',
    功能:[]
}